use clap::Args;
use log::LevelFilter;
use serde::{Deserialize, Serialize};
use std::{fs::{File, OpenOptions}, io::Write};
use simplelog::{format_description, CombinedLogger, ConfigBuilder, SharedLogger, TermLogger, WriteLogger};
use time::UtcOffset;
use chrono::Local;


pub type DateTime = chrono::DateTime<chrono::Local>;
pub const WTASK_BASIC_FILE_NAME: &str = "wtask";


struct LogFile {
    num: usize,
    num_max: usize,
    file: File,
    file_path: String,
}

impl LogFile {
    fn new(file_path: &str, flush_num: usize) -> Self {
        Self {
            num: 0,
            num_max: flush_num,
            file: Self::get_file(file_path),
            file_path: file_path.to_owned(),
        }
    }

    fn file_path(file_path: &str) -> String {
        format!(
            "{}.{}.log",
            file_path,
            // Local::now().format("%Y_%m_%d_%H_%M_%S")
            Local::now().format("%Y%m")
        )
    }

    fn get_file(file_path: &str) -> File {
        let file_path = Self::file_path(file_path);
        OpenOptions::new()
            .append(true)  // 设置追加模式
            .create(true)  // 如果文件不存在，则创建文件
            .open(file_path)
            .unwrap()
    }
}



impl Write for LogFile {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.file.write(buf)
    }
    
    fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
        self.file.write_all(buf)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        let _ = self.file.flush();
        self.num += 1;
        if self.num > self.num_max {
            self.file = Self::get_file(&self.file_path);
        }
        Ok(())
    }
}


#[derive(Debug, Clone, Args, Serialize, Deserialize)]
pub struct LogArgs {
    /// 关闭终端日志输出
    #[arg(long)]
    pub noterminal: bool,
}



pub fn log_init(log_args: &LogArgs) {
    let log_level = LevelFilter::Info;
    let conf_log = ConfigBuilder::new()
        .set_time_format_custom(format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]"))
        .set_time_offset(UtcOffset::from_whole_seconds(Local::now().offset().local_minus_utc()).unwrap())
        .set_max_level(log_level)
        .set_location_level(log_level)
        .build();

    let logger_file = WriteLogger::new(
        log_level,
        conf_log.clone(),
        LogFile::new(WTASK_BASIC_FILE_NAME, 8)
    );
    let logger_vec: Vec<Box<dyn SharedLogger>> = if !log_args.noterminal {
        let logger = TermLogger::new(
            log_level,
            conf_log,
            simplelog::TerminalMode::Mixed,
            simplelog::ColorChoice::Auto
        );
        vec![logger, logger_file]
    } else {
        vec![logger_file]
    };

    CombinedLogger::init(logger_vec).unwrap();
}


pub static TIME_FORMAT_FULL: &str = "%Y-%m-%d %H:%M:%S.%f";
pub static TIME_FORMAT_TIME: &str = "%Y-%m-%d %H:%M:%S";
pub static TIME_FORMAT_TIMELINE: &str = "%Y_%m_%d_%H_%M_%S";


pub fn log_format(data: String) -> String {
    format!("[{}] {}", Local::now().format(TIME_FORMAT_FULL), data)
}

pub fn log_format_str(data: &str) -> String {
    log_format(data.to_string())
}